package com.zyw.teacher.config;

import com.alibaba.fastjson.JSON;
import com.zyw.common.RespResult;
import com.zyw.teacher.login.service.impl.AuthenticationAccessDeniedHandler;
import com.zyw.teacher.login.service.impl.DataBaseFilterInvocationSecurityMetadataSource;
import com.zyw.teacher.login.service.impl.DataBaseManagerToken;
import com.zyw.teacher.login.service.impl.DateAccessDecisionManager;
import com.zyw.teacher.login.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;

import java.io.PrintWriter;

/**
 * @Description:
 * @Author: zyw
 * @Date: 2018/12/4
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**白名单*/
    private static final String[] whiteList = {"/","/login"};

    @Autowired
    private AuthenticationAccessDeniedHandler deniedHandler;

    /**
     * 覆写该方法，该方法限制了哪些URL需要权限控制，哪些不用
     * @param http HttpSecurity
     * @Author: zyw
     * @result
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            /**配置所有权限*/
            /** method allows granting access to all users for all URLs associated with form based log in. and http based log in*/
            .antMatchers(whiteList).permitAll()
            .and().formLogin().loginPage("/login")
                .failureHandler(((request, response, exception) -> {
                    response.setContentType("application/json;charset=utf-8");
                    RespResult resp = new RespResult();
                    if (exception instanceof BadCredentialsException ||
                            exception instanceof UsernameNotFoundException) {
                            resp.addError("账户名或者密码输入错误!");
                    } else if (exception instanceof LockedException) {
                            resp.addError("账户被锁定，请联系管理员!");
                    } else if (exception instanceof CredentialsExpiredException) {
                            resp.addError("密码过期，请联系管理员!");
                    } else if (exception instanceof AccountExpiredException) {
                            resp.addError("账户过期，请联系管理员!");
                    } else if (exception instanceof DisabledException) {
                            resp.addError("账户被禁用，请联系管理员!");
                    } else {
                            resp.addError("登录失败!");
                    }
                    response.setStatus(401);
                    PrintWriter out = response.getWriter();
                    out.write(JSON.toJSONString(resp));
                    out.flush();
                    out.close();}))
                .successHandler(((request, response, authentication) -> {
                    response.setContentType("application/json;charset=utf-8");
                    RespResult resp = new RespResult();
                    resp.addSuccess("登录成功!");
                    PrintWriter out = response.getWriter();
                    out.write(JSON.toJSONString(resp));
                    out.flush();
                    out.close();
                }))
            /**设置登录页url 如果不设置使用得是默认得页面
            .loginPage("/login")
            .permitAll()*/
            .and()
            .logout()
            .permitAll()
            .and().exceptionHandling().accessDeniedHandler(deniedHandler)
            /**由于采用前后端分离，前端和后端是不同端口，一定存在跨域问题。CSRF是为了防止跨域访问，因此关闭跨域保护*/
            .and().csrf().disable();
    }

    /**
     * 用户信息
     * @Author: zyw
     * @result
     */
    @Bean
    @Override
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    /**
     * 权限管理
     * @Author: zyw
     * @result
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManager(){
        return new DataBaseManagerToken();
    }

    /**
     * 根据请求返回请求资源对应的角色列表
     * @Author: zyw
     * @result 
     */
    @Bean
    public FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource(){
        return new DataBaseFilterInvocationSecurityMetadataSource();
    }

    /**
     * 根据登录信息和请求资源对应的角色列表判断是否有权限访问资源
     * @Author: zyw
     * @result
     */
    @Bean
    public AccessDecisionManager accessDecisionManager(){
        return new DateAccessDecisionManager();
    }
}
